#include "RtBase.h"
#include "RtCnPkgSender.h"

#if !defined (_NEW_PROTO_TP)

CPkgSender::CPkgSender(CRtConnectionManager::CType)
{
	m_pmbLocSendData = NULL;

	m_disconn_timestamp = CRtTimeValue::GetTimeOfDay();

	m_cType = CRtConnectionManager::CTYPE_SEND_NO_PARTIAL_DATA;

	m_pConnConnector = NULL;
}

CPkgSender::~CPkgSender()
{
	m_timer.Cancel();
	Reset();
}

void CPkgSender::TryOnDisconnIndicate()
{
	//Only RlbTcpServer may do
	return;
}

void CPkgSender::NeedKeepAlive(BOOL bNeedKeepAlive)
{
	//Do nothing
	return;
}

void CPkgSender::SetConnConnector(CPkgSenderConnector* pConnConnector)
{
	
	m_pConnConnector = pConnConnector;
}

void CPkgSender::CancelHandShake()
{
	//Do nothing
	return;
}

void CPkgSender::Reset()
{
	if(m_pmbLocSendData)
	{
		m_pmbLocSendData->DestroyChained();
		m_pmbLocSendData = NULL;
	}
	CRtConnBase::Release();
}

RtResult CPkgSender::SendData_i() 
{
	RtResult result = RT_OK;

	//DWORD dwLenBeforeSend, dwLenAfterSend = 0;
	
	if(m_pmbLocSendData == NULL)
		return RT_OK;

	if(m_pmbLocSendData->GetChainedLength() > 0)//Data can send
	{
		//dwLenBeforeSend = m_pmbLocSendData->GetChainedLength();
		result = m_lowerTransport->SendData(*m_pmbLocSendData);
		//dwLenAfterSend = m_pmbLocSendData->GetChainedLength();
		
		//RT_INFO_TRACE("CPkgSender::SendData_i(), Data piece sent " << dwLenBeforeSend - dwLenAfterSend << " Bytes");
	}

	return result;
}

RtResult CPkgSender::SendData(
		CRtMessageBlock& inData,
		BOOL inSendImmediately,
		BOOL inDestroyData,
		DataPriority inPriority, 
		BOOL inNeedAck)
{
	if(m_status != STATUS_DATA_CAN_SEND)
		return RT_ERROR_NOT_AVAILABLE;//Cannot send data now

	RT_ASSERTE_RETURN(inData.GetChainedLength() > 0, RT_OK);

	RtResult result = RT_OK;
		
	if(m_pmbLocSendData->GetChainedLength() > 0)
		result = RT_ERROR_PARTIAL_DATA;
	
	if(RT_SUCCEEDED(SendData_i()))
	{
		result = RT_OK;
		
		if(m_pmbLocSendData == NULL)
		{
			m_pmbLocSendData = inData.DuplicateChained();
			inData.AdvanceChainedReadPtr(inData.GetChainedLength());
		}
		else if(m_pmbLocSendData->GetChainedLength() == 0)
		{
			m_pmbLocSendData->DestroyChained();
			m_pmbLocSendData = inData.DuplicateChained();
			
			inData.AdvanceChainedReadPtr(inData.GetChainedLength());
		}
		
		SendData_i();
	}
	
	if (RT_SUCCEEDED(result) && inDestroyData)
		inData.DestroyChained();

	return result;
}

RtResult CPkgSender::SetOption(
								  DWORD aCommand, 
								  LPVOID aArg)
{
	if(m_lowerTransport)
		return m_lowerTransport->SetOption(aCommand, aArg);

	return RT_ERROR_NOT_AVAILABLE;
}

RtResult CPkgSender::GetOption(
								  DWORD aCommand, 
								  LPVOID aArg)
{
	RtResult rv = RT_ERROR_NOT_AVAILABLE;

	switch(aCommand)
	{
	case RT_OPT_TRANSPORT_TRAN_TYPE:

		if(m_lowerTransport)
		{
			DWORD dwTransType;

			rv = m_lowerTransport->GetOption(
				RT_OPT_TRANSPORT_TRAN_TYPE, 
				(LPVOID)&dwTransType);

			if(RT_SUCCEEDED(rv))
			{
				*(static_cast<CRtConnectionManager::CType*>(aArg)) 
				= CRtConnectionManager::CTYPE_SEND_NO_PARTIAL_DATA | dwTransType;

				rv = RT_OK;
			}
		}
			
		return rv;
		
	default:
		if(m_lowerTransport)
			return m_lowerTransport->GetOption(aCommand, aArg);

		return RT_ERROR_NOT_AVAILABLE;
	}
}

RtResult CPkgSender::Disconnect(
								   RtResult aReason)
{
	m_sink = NULL;
	return m_lowerTransport->Disconnect(aReason);
}

void CPkgSender::OnReceive(
							  CRtMessageBlock &aData,
							  IRtTransport *aTrptId,
							  CRtTransportParameter *aPara)
{
	//Call back directly
	if(m_sink)
		m_sink->OnReceive(aData, this, aPara);
}

void CPkgSender::OnSend(
						   IRtTransport *aTrptId,
						   CRtTransportParameter *aPara)
{
	RT_INFO_TRACE_THIS("CPkgSender::OnSend");
	
	SetStatus(STATUS_DATA_CAN_SEND);
	SendData_i();

	if(m_sink)
	{
		//RT_INFO_TRACE("CPkgSender::OnSend(), TP OnSend()");
		m_sink->OnSend(this, aPara);
	}
}

void CPkgSender::OnDisconnect(
								 RtResult aReason,
								 IRtTransport *aTrptId)
{
	//RT_INFO_TRACE("CPkgSender::OnDisconnect reason = " << aReason << " transport = " << aTrptId);
	SetStatus(STATUS_UNCONNECTED);

	m_lowerTransport->Disconnect((RtResult)RT_ERROR_NETWORK_CONNECT_ERROR);
	
	if(m_sink)
		m_sink->OnDisconnect(aReason, this);

	m_sink = NULL;

	//Waiting for a short time to be Removed
	m_disconn_timestamp = 
		CRtTimeValue::GetTimeOfDay() - CRtTimeValue(SERVER_NORMAL_DISCONN_TIMEOUT, 0);
}

void CPkgSender::OnTimer(CRtTimerWrapper* aId)
{
	//Timer is no need here
	return;
}

// interface IRtAcceptorConnectorSink
void CPkgSender::OnConnectIndication(
										RtResult aReason,
										IRtTransport *aTrpt,
										IRtAcceptorConnectorId *aRequestId)
{
//	RT_INFO_TRACE("CPkgSender::OnConnectIndication(), m_lowerTransport = " << m_lowerTransport << ", aTrpt = " << aTrpt);
	
	if(m_pConnConnector)//Connector case
	{
		RT_ASSERTE(m_pConnConnector->GetTPConnector() == aRequestId);
		
		if(RT_SUCCEEDED(aReason))
		{
			m_lowerTransport = aTrpt;

			m_lowerTransport->OpenWithSink(this);

			//Physical connection make, and data can be sent now
			SetStatus(STATUS_DATA_CAN_SEND);
			
			//Callback to Upper layer
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				aReason, 
				this, 
				m_pConnConnector);
			
			//Get Transport type
			DWORD dwTransType;

			if(m_lowerTransport)
				m_lowerTransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, (LPVOID)&dwTransType);
		}
		else //There are errors, such as timeouted
		{
			//Callback to Upper layer
			m_pConnConnector->GetConnectorSink()->OnConnectIndication(
				aReason, 
				NULL, 
				m_pConnConnector);
		}

		return;
	}

	if(m_pConnAcceptor.Get())//Acceptor case
	{
		RT_ASSERTE(m_pConnAcceptor->GetTPAcceptor() == aRequestId);
		
		m_lowerTransport = aTrpt;
		
		aTrpt->OpenWithSink(this);
		
		SetStatus(STATUS_DATA_CAN_SEND);
		
		//Callback to Upper layer
		m_pConnAcceptor->GetAcceptorSink()->OnConnectIndication(
			aReason, 
			this, 
			m_pConnAcceptor.ParaIn());

		//Get Transport type
		DWORD dwTransType = CRtConnectionManager::CTYPE_NONE;
		
		if(m_lowerTransport)
			m_lowerTransport->GetOption(RT_OPT_TRANSPORT_TRAN_TYPE, (LPVOID)&dwTransType);
		
		return;
	}
}

void CPkgSender::SetServerList(CPkgSenderServerList *pSvrList)
{
	m_pSvrList = pSvrList;
}

void CPkgSender::SetConnAcceptor(CPkgSenderAcceptor* pConnAcceptor)
{
	m_pConnAcceptor = pConnAcceptor;
}

CRtTimeValue CPkgSender::GetDisconnTimestamp()
{
	return m_disconn_timestamp;
}

#endif
